import time
import pytz
import json
import os
import logging
import traceback

from absl import app, flags
from datetime import datetime, timedelta
import coin.base.database.util as db_util
from coin.support.accounting.logic.key_util import get_key_file
from coin.base.datetime_util import to_timestamp_int
from coin.proto.coin_request_pb2 import AccountInfoProto
from coin2.exchange.order.system_pb2 import OrderSystemConfig
from coin.exchange.base.kr_rest.py_private_client import PyPrivateClient
from google.protobuf.json_format import ParseDict
from coin.proto.coin_query_pb2 import CurrencyTransferBundle
from coin.base.param_util import split_string
from coin.support.accounting.logic.query_util import \
    filter_invalid_request_and_result
from xunkemgmt_client.support.accounting.database.mysql_importer import \
    MysqlAccountInfoImporter as MysqlImporter
from xunkemgmt_client.support.accounting.database.db_output import DBOutputTransfer
from xunkemgmt_client.client.util.query_util import query_accounts


FLAGS = flags.FLAGS


def os_config_driver(key_filepath, market_type, exchange, api_version):
  key_filepath = os.path.abspath(key_filepath)
  if market_type in ('ExWallet', 'Margin'):
    pi_mea = f'Spot.{exchange}.{api_version}'
  else:
    pi_mea = f'{market_type}.{exchange}.{api_version}'
  pi_file = f'data/coin2/product_info/{pi_mea}.json'
  with open(pi_file) as f:
    pi = json.load(f)
    assert pi_mea == pi['mea'], (pi_mea, pi['mea'])
    norms = [product['symbol'] for product in pi['product_infos']]
  os_config = {
      'mea': pi['mea'],
      'products': {
        'norms': norms
      },
      'connection_config': {
        'key_filepath': key_filepath
      }
  }
  os_config_proto = OrderSystemConfig()
  ParseDict(os_config, os_config_proto)
  return os_config_proto


def _check_transfer_list(request_list, response_list):
  assert len(request_list) == len(response_list)
  for idx in range(len(request_list)):
    if request_list[idx].market_type != response_list[idx].transfer.market_type or \
       request_list[idx].exchange != response_list[idx].transfer.exchange:
      raise ValueError('transfer list order mismatch')
  return


def collect_hist_transfer(request_list, start_time, end_time):
  response_list = []
  for request in request_list:
    market_type = request.market_type
    exchange = request.exchange
    owner = request.owner
    api_version = request.api_version
    key_root = None
    if request.business_unit == 'DigitalFund':
      key_root = '../../fund_key/view'
    key_filepath = get_key_file(market_type, exchange, owner, api_version, "view", key_root=key_root)
    os_config = os_config_driver(key_filepath, market_type, exchange, api_version)
    client = PyPrivateClient(os_config)
    transfer_hist = client.query_transfer_histories(
      to_timestamp_int(start_time), to_timestamp_int(end_time))
    transfer_hist = sorted(transfer_hist, key=lambda x: x.create_timestamp)
    transfer_bundle = CurrencyTransferBundle(
        market_type = market_type,
        exchange = exchange,
        each_transfer = transfer_hist
    )
    transfer_result = DBOutputTransfer(
        query_timestamp=time.time(),
        transfer=transfer_bundle
    )
    response_list.append(transfer_result)
  return response_list


def insert_hist_transfer_db(request_list, response_list, config_path):
  _check_transfer_list(request_list, response_list)
  db_config = db_util.read_db_config(config_path)
  importer = MysqlImporter(db_config=db_config)
  importer.upsert_transfer_history(request_list, response_list)


def main(_):
  end_date = datetime.strptime(FLAGS.end_date, '%Y%m%d').replace(
    tzinfo=pytz.UTC) if FLAGS.end_date else datetime.now()
  start_date = datetime.strptime(FLAGS.start_date, '%Y%m%d').replace(
    tzinfo=pytz.UTC) if FLAGS.start_date else end_date - timedelta(days=7)
  request_list = query_accounts(active=True,
                                business_units=split_string(FLAGS.business_unit),
                                market_types=split_string(FLAGS.market_type),
                                exchanges=split_string(FLAGS.exchange),
                                owners=split_string(FLAGS.owner),
                                as_proto=True)
  request_list = [request for request in request_list 
    if request.account_type == AccountInfoProto.MASTER]

  response_list = collect_hist_transfer(request_list, start_date, end_date)
  filtered_request_list, filtered_response_list = \
    filter_invalid_request_and_result(request_list, response_list)
  print(f"{FLAGS.start_date}-{FLAGS.end_date} " + \
     f"historical transfer\n{filtered_response_list}")
  insert_hist_transfer_db(filtered_request_list, filtered_response_list, FLAGS.mysql_config)


if __name__ == '__main__':
  flags.DEFINE_string('business_unit', 'Coin,DigitalFund', 'transfer account biz unit')
  flags.DEFINE_string('market_type', None, 'transfer account market type')
  flags.DEFINE_string('exchange', None, 'transfer account exchange')
  flags.DEFINE_string('owner', None, 'transfer account')
  flags.DEFINE_string('start_date', None, '%Y%m%d')
  flags.DEFINE_string('end_date', None, '%Y%m%d')
  flags.DEFINE_string('mysql_config',
                      "../../coin_deploy/support_accounting/db_config/mysql_config_prod.json",
                      'path of database config.')
  app.run(main)
